package com.wanji.gateway.protocol;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 动态类加载器，用于加载指定目录下的JAR包
 */
public class DynamicClassLoader extends URLClassLoader {
    private static final Logger log = LoggerFactory.getLogger(DynamicClassLoader.class);
    private final List<File> jarFiles = new ArrayList<>();

    public DynamicClassLoader(String sdkDir, ClassLoader parent) throws IOException {
        super(new URL[0], parent);
        loadJarFiles(sdkDir);
    }

    /**
     * 加载指定目录下的所有JAR包
     */
    private void loadJarFiles(String sdkDir) throws IOException {
        File dir = new File(sdkDir);
        if (!dir.exists() || !dir.isDirectory()) {
            log.warn("SDK目录不存在或不是目录: {}", sdkDir);
            return;
        }

        log.info("正在扫描SDK目录: {}", sdkDir);
        List<File> newJarFiles = new ArrayList<>();
        File[] files = dir.listFiles();
        if (files == null || files.length == 0) {
            return;
        }

        // 遍历目录下的所有文件
        for (File file : files) {
            if (file.isFile() && file.getName().endsWith(".jar")) {
                newJarFiles.add(file);
                addURL(file.toURI().toURL());
                log.info("已加载JAR包: {}", file.getName());
            }
        }

        this.jarFiles.clear();
        this.jarFiles.addAll(newJarFiles);
        log.info("共加载 {} 个JAR包", newJarFiles.size());
    }

    /**
     * 扫描JAR包中的指定类型
     */
    public <T> List<Class<? extends T>> scanForType(String jarPath, Class<T> type) {
        List<Class<? extends T>> result = new ArrayList<>();
        File jarFile = new File(jarPath);

        if (!jarFile.exists()) {
            log.warn("JAR文件不存在: {}", jarPath);
            return result;
        }

        try (JarFile jar = new JarFile(jarFile)) {
            Enumeration<JarEntry> entries = jar.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String className = entry.getName();

                // 只处理类文件
                if (className.endsWith(".class") && !entry.isDirectory()) {
                    className = className.replace('/', '.').substring(0, className.length() - 6);

                    try {
                        Class<?> clazz = loadClass(className);
                        if (type.isAssignableFrom(clazz) && !clazz.equals(type)) {
                            @SuppressWarnings("unchecked")
                            Class<? extends T> implClass = (Class<? extends T>) clazz;
                            result.add(implClass);
                            log.info("发现协议实现: {}", className);
                        }
                    } catch (Throwable t) {
                        log.error("加载类失败: {}", className, t);
                    }
                }
            }
        } catch (IOException e) {
            log.error("扫描JAR包失败: {}", jarPath, e);
        }

        return result;
    }

    /**
     * 重新加载JAR包
     */
    public void reloadJarFiles(String sdkDir) throws IOException {
        // 关闭当前类加载器
        close();

        // 创建新的类加载器
        URL[] urls = getURLs();
        for (URL url : urls) {
            log.info("关闭类加载: {}", url.getFile());
        }

        // 重新加载JAR包
        loadJarFiles(sdkDir);
        log.info("JAR包重新加载完成");
    }
}